package org.cypress.rtpack.service;
import org.cypress.rtpack.VO.arrPar;
import org.cypress.rtpack.entity.RtpackConfig;
import org.cypress.rtpack.entity.RtpackMoniip;
import org.cypress.rtpack.utils.APIChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.cypress.rtpack.utils.FotterUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import javax.annotation.PreDestroy;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;


@Service
public class CommMoniService {
    @Autowired
    private IRtpackConfigService rtpackConfigService;
    @Autowired
    private IRtpackMoniipService rtpackMoniipService;

    private static final Logger logger = LoggerFactory.getLogger(CommMoniService.class);
    private static int try_times_fail = 1;  //连续探测几次给报警

    public static boolean fastDetecting = false;
    private static int fastDetecingKeep = 0;
    public static boolean[] rom1 = new boolean[100]; // 默认值全部为 false
    private static int[] rom1Keep = new int[100];
    private final ReentrantLock lockerDkIn = new ReentrantLock();

    @Autowired
    @Qualifier("periodicTaskExecutor")
    private ExecutorService executor;

    private final ConcurrentMap<Integer, Future<?>> taskFutures = new ConcurrentHashMap<>();

    public void startMonitor() {
        logger.info("CommMoni detecting starting...");

        try {
            RtpackConfig rtpackConfig_inst1 = rtpackConfigService.getByKey("try_times_fail");
            if (rtpackConfig_inst1 != null && rtpackConfig_inst1.getValue() != null) {
                try_times_fail = Integer.parseInt(rtpackConfig_inst1.getValue());
                logger.info("从数据库读取try_times_fail={}", try_times_fail);
            } else {
                logger.info("从数据库未读取到try_times_fail，采用默认值1.");
            }
        } catch (Exception e) {
            logger.info("从数据库读取try_times_fail失败，采用默认值1。错误原因: " + e.getMessage());
        }

        boolean[] dk_in = new boolean[100];
        boolean[] dk_in_u = new boolean[100]; // 用于保存快照的副本

        boolean yusDec = true;
        while(yusDec) {
            try{
                lockerDkIn.lock();
                try {
                    // 使用System.arraycopy进行高效复制
                    System.arraycopy(dk_in, 0, dk_in_u, 0, dk_in.length);

                    // 或者使用Arrays.copyOf（内部其实也是调用System.arraycopy）
                    // dk_in_u = Arrays.copyOf(dk_in, dk_in.length);
                    Arrays.fill(dk_in, true);
                } finally {
                    lockerDkIn.unlock(); // 确保锁一定会释放
                }

                List<RtpackMoniip> rtpackMoniipList = rtpackMoniipService.getAll();
                rtpackMoniipList.forEach(item -> {
                    int th = item.getAddtohmi();
                    if(item.isDisable()){  //被禁用，跳过当前IP进入下一个
                        rom1[th] = false;
                        return;   //Lambda表达式实现时不能使用continue;
                    }
                    if(!dk_in_u[th]) {
                        final int taskId = th;
                        // 使用 AtomicInteger 保证线程安全
                        //final AtomicInteger myPos = new AtomicInteger(0);
                        Future<?> future = executor.submit(() -> {
                            String devIP = item.getIP();
                            String method = item.getMethod();
                            boolean detectingSuc = false;
                            if (method.equals("mdbstcp")) {        //mdbstcp
                                Socket socket = null;
                                OutputStream out = null;
                                InputStream in = null;
                                int devPort = item.getPort();
                                try {
                                    //int curPos = myPos.get();
                                    // 创建Socket连接
                                    socket = new Socket(item.getIP(), devPort);
                                    socket.setSoTimeout(3000);

                                    // 获取输出流发送字节数组
                                    out = socket.getOutputStream();
                                    int staA = item.getStartadd();
                                    int lenV = item.getCount();
                                    ByteBuffer buffer4A = ByteBuffer.allocate(4);
                                    buffer4A.putShort((short) staA); // 写入 staA（2字节）
                                    buffer4A.putShort((short) lenV); // 写入 lenV（2字节）
                                    byte[] bytesT = buffer4A.array();
                                    byte func = item.getFunc();
                                    byte[] requestData = {99, 99, 0, 0, 0, 6, item.getSlvid(), func, bytesT[0], bytesT[1], bytesT[2], bytesT[3]};

                                    int respectLen = 0;
                                    if(func > 2){
                                        respectLen = 2 * lenV + 9;
                                    } else {
                                        int yu = (lenV - 1) % 8;
                                        int byteC = (lenV - 1 - yu) / 8 + 1;
                                        respectLen = byteC + 9;
                                    }

                                    out.write(requestData);
                                    out.flush();

                                    // 获取输入流读取响应
                                    in = socket.getInputStream();
                                    byte[] buffer = new byte[264];
                                    int bytesRead = in.read(buffer);

                                    if (bytesRead == respectLen) {
                                        detectingSuc = true;
                                    }
//                                    String recvStr = "";
//                                    for(int i = 0; i < bytesRead; i++){
//                                        recvStr += String.format("%02X", buffer[i]) + " ";
//                                    }
//                                    logger.info("Task-{} recv data | {}", taskId, recvStr);

                                    //myPos.set(curPos);
                                } catch (SocketTimeoutException e) {
                                    //logger.info("Task-{} socket timeout | {}:{}", taskId, devIP, devPort);
                                } catch (Exception e) {
                                    //logger.info("Task-{} socket error | {}:{}", taskId, devIP, devPort);  //或者e.getMessage()
                                    //e.printStackTrace(); // 打印完整的异常堆栈信息
                                } finally {
                                    // 确保资源被正确关闭
                                    try {
                                        if (in != null) in.close();
                                        if (out != null) out.close();
                                        if (socket != null) socket.close();
                                    } catch (Exception e) {
                                        //logger.info("Task-{} close error", taskId);
                                    }
                                }
                            } else if (method.contains("api")){
                                String decideStandard = "";
                                String assFunc = "";
                                if (method.contains(":") && method.contains("=")){
                                    String[] parts = method.split(":", 3);
                                    decideStandard = parts[1];
                                    if (parts.length > 2){
                                        assFunc = parts[2];
                                    }
                                }
                                arrPar arrPar1 = APIChecker.IsAPIHealty(item.getIP(),decideStandard,assFunc);
                                detectingSuc = arrPar1.getVb(0);
                                if (detectingSuc && assFunc.contains("|")){
                                    for(int i = 1; i < 5; i++){
                                        int iThis = arrPar1.getVi(i);
                                        if((iThis >= 0) && (iThis <= 99)){
                                            rom1[iThis] = arrPar1.getVb(i);
                                        }
                                    }
                                }
                            }
                            else if (method.contains("ping")){    //ping检测
                                detectingSuc = FotterUtils.pingReachable(item.getIP());
                            }
                            else{
                                detectingSuc = false;
                            }
                            if (detectingSuc) {
                                rom1[taskId] = false;
                                rom1Keep[taskId] = 0;
                            } else {
                                if (rom1Keep[taskId] < 100) {
                                    rom1Keep[taskId]++;
                                }
                                if (rom1Keep[taskId] >= try_times_fail) {   //连续探测几次失败则报警
                                    rom1[taskId] = true;
                                }
                            }
                            // 在while循环最后添加5000ms休眠
                            try {
                                TimeUnit.MILLISECONDS.sleep(100);
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                                logger.info("Task-{} sleep interrupted", taskId);
                            }

                            taskFutures.remove(taskId);
                            lockerDkIn.lock();
                            dk_in[taskId] = false;
                            lockerDkIn.unlock();
                        });
                        taskFutures.put(taskId, future);
                    }
                    try {
                        TimeUnit.MILLISECONDS.sleep(20);     //将任务错开执行
                    } catch (InterruptedException e) {
                        logger.info("CommMoni Start task delay error");
                    }
                });  //rtpackMoniipList.forEach(item -> {   ***   });
                MdbsSlv1Service.unreply_After_Err = 0;
            } catch (Exception e){
                logger.info("从数据库读取MoniipList失败。错误原因: " + e.getMessage());
                if (MdbsSlv1Service.unreply_After_Err < 20){
                    MdbsSlv1Service.unreply_After_Err++;
                    logger.info("MdbsSlv1Service.unreply_After_Err= {}，如果>9将不应答HMI请求", MdbsSlv1Service.unreply_After_Err);
                }
            }
            try {
                TimeUnit.MILLISECONDS.sleep(5000);     //将任务错开执行
            } catch (InterruptedException e) {
                logger.info("Periodic Start task delay error");
            }
        }    //while(yusDec)
    }

    public void stopTask(int taskId) {
        Future<?> future = taskFutures.get(taskId);
        if (future != null) {
            future.cancel(true);
            taskFutures.remove(taskId);
        }
    }

    @PreDestroy
    public void shutdown() {
        taskFutures.values().forEach(f -> f.cancel(true));
        executor.shutdown();
    }
}